
#include "shading.fx"
#include "samplers.fx"
#include "fog.fx"

struct VS_IN
{
	float3 position : POSITION;
	float3 normal	: NORMAL;
	float3 tangent : TANGENT;
	float2 tex		: TEX_COORDS;
};

struct VS_OUT
{
	float4 position : SV_POSITION;
	float4 ws_pos	: WS_POSITION;
	float3 normal	: NORMAL;
	float3 tangent  : TANGENT;
	float2 tex		: TEX_COORDS;
};

float	fFrozenReflectivity = 0.1f;
float	fNormalReflectivity = 0.9f;

float4x4 m_World;
float4x4 m_WorldViewProj;
float4x4 m_Tex;

Texture2D tex_reflections;
Texture2D tex_refractions;

Texture2D tex_sea0_normalmap;
Texture2D tex_sea1_normalmap;

Texture2D tex_ice_heightmap;
Texture2D tex_ice;

int reflection_tex_width;
int reflection_tex_height;

float ice_percentage;
float3	windDir;
float fWindPower;
bool flag;

bool bFrozen;

float wave_t;

static const float speed = 0.6f;

float wave_height;
float radius;

VS_OUT VS(VS_IN vin)
{
	VS_OUT vout;

	vout.position = mul(float4(vin.position, 1.0f), m_WorldViewProj);
	vout.ws_pos = mul(float4(vin.position, 1.0f), m_World);
	vout.normal = mul(float4(vin.normal, 0.0f), m_World).xyz;
	vout.tangent = mul(float4(vin.tangent, 0.0f), m_World).xyz;
	vout.tex =	  mul(float4(vin.tex, 0.0f, 1.0f), m_Tex).xy;

	return vout;
}


VS_OUT VS_DisplacementMapping(VS_IN vin)
{
	VS_OUT vout;

	float near = 1.35f;
	float far  = 4.0f;

	float minWaveHeight = 0.0f;
	float maxWaveHeight = 0.2f;
	float windEffect = lerp(minWaveHeight, maxWaveHeight, fWindPower); 


	// y offset
	float3 displaced_pos = vin.position;
	displaced_pos.y = cos(displaced_pos.x*10 - wave_t) * windEffect;
	
	float d = length(vin.position.xz*radius);
	displaced_pos.y = lerp(displaced_pos.y, 0.0f, (far-d)/(far-near)) * wave_height;

	// rotation
	float dotP = dot(windDir, float3(1,0,0));
	float angle = acos(dotP);

	float2x2 mtxRotate = float2x2(	cos(angle), -sin(angle),
									sin(angle),	 cos(angle)
								);
							
	displaced_pos.xz = mul(displaced_pos.xz, mtxRotate);


	float x = displaced_pos.x*10 - wave_t;

	float3 normal = (float3)0;
	
	float dX = -10.0f * 0.5f*windEffect * sin(x);

	if (dX == 0.0f)
		normal = float3(0,1,0);
	else 
		normal = float3(-dX, 1, 0); 	//tangent = float3(1, dX, 0) -> normal = (-t.y, t.x, 0)
	
	// rotate normal
	normal.xz = mul(normal.xz, mtxRotate);
	normal = normalize(normal);

	if (wave_height < 0.2f)
		normal = float3(0,1,0);

	// rest of vsout values
	vout.position = mul(float4(displaced_pos, 1.0f), m_WorldViewProj);
	vout.ws_pos = mul(float4(displaced_pos, 1.0f), m_World);
	vout.normal = normal;
	vout.tangent = mul(float4(vin.tangent, 0.0f), m_World).xyz;
	vout.tex = vin.tex;
	return vout;
}




float4 PS(VS_OUT pin) : SV_TARGET
{
	
	float d = radius - length(pin.ws_pos);
	clip(d);

	float3 v_tan = float3(1,0,0);
	float3 wNormal = float3(0,0,0);

	if (mat_params.vIsTextured.z) // normal
	{		
		float3 normal0 = tex_sea0_normalmap.Sample(s_linear, pin.tex).xyz;
		float3 normal = normalize(normal0);
	
		float3 T = normalize(v_tan);
		float3 N = float3(0,1,0);
		float3 B = cross(T, N);
		T = cross(N, B);

		float3x3 m = float3x3(T, B, N);
		wNormal = mul(normal, m);

	}
	else
		wNormal = pin.normal;

	float s = dot(normalize(wNormal), normalize(-lights[0].direction.xyz));

	// color = shade() : diffuse+specular
	float4 color = float4(shade(pin.ws_pos.xyz, normalize(pin.normal), 0), 1.0f);

	
	float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);

	// color	= color	   * tex_diffuse
	// ambient	= ambient  * tex_diffuse
	if (mat_params.vIsTextured.x)
	{
		float4 tex_diff = tex_diffuse.Sample(s_linear, pin.tex);
		
		float ice_height = tex_ice_heightmap.Sample(s_linear, pin.tex).r;

		float4 ice = tex_ice.Sample(s_linear, pin.tex);


		float r = min(ice_percentage, 0.8f);

		if (ice_height <= r)
			color *= ice;
		else
			color *= tex_diff;
	}

	// set alpha in w
	color = float4(color.xyz, mat_params.diffuse.w);


	// color = color + ambient
	color += ambient;

	// Reflection
	float x = (pin.position.x - 0.5f) / (float)reflection_tex_width;
	float y = (pin.position.y - 0.5f) / (float)reflection_tex_height;
	
	// fresnel
	float fresnel_term = 0.0f;

	float3 eye_vector = normalize(pEye - pin.ws_pos.xyz);

	float fangle = 1.0f + dot(eye_vector, float3(0,1,0));
	fangle = pow(fangle ,5);
	fresnel_term = 1/fangle;
	

	float2 pert = float2(0,0);

	if (ice_percentage < 0.000001f)
	{
		pert = wNormal.xz - float2(0.5f, 0.5f);
		pert *= float2(0.032f, 0.032f) * 2.0f;
	}
	else
		pert = float2(0.0f, 0.0f);
	
	float a = abs(pert.x) + abs(pert.y);
	

	float4 reflection_color = float4(0,0,0,1);
	float4 refraction_color = float4(0,0,0,1);

	reflection_color = tex_reflections.Sample(s_linear, float2(x,y) + pert);   
	refraction_color = tex_refractions.Sample(s_linear, float2(x,y) + pert);

	float4 final_color = fresnel_term * reflection_color + (1.0f - fresnel_term) * refraction_color;
	
	float4 sea_color = color;
	
	float lerp_factor = lerp(fNormalReflectivity, fFrozenReflectivity, ice_percentage);
	final_color = lerp(sea_color, final_color, lerp_factor);
	

	final_color = computeFog(final_color, pin.ws_pos.xyz, pin.ws_pos.y, 3.0f, pEye);


	return float4(final_color.xyz, final_color.w);

}


RasterizerState rs_cullBack
{
	CullMode = Back;
};

RasterizerState rs_Wireframe
{
	CullMode = Back;
	FillMode = Wireframe;
};

BlendState bs_transparent
{
	AlphaToCoverageEnable = false;
	BlendEnable[0] = true;
	

	SrcBlend[0] = SRC_ALPHA;
	DestBlend[0] = INV_SRC_ALPHA;
	BlendOp[0] = ADD;

	SrcBlendAlpha[0] = ONE;
	DestBlendAlpha[0] = ZERO;
	BlendOpAlpha[0] = ADD; 
};

technique10 Sea
{
    pass P0 
	{
        SetVertexShader( CompileShader( vs_4_0, VS_DisplacementMapping() ) );
		SetGeometryShader( NULL);
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
		
		SetBlendState(bs_transparent, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff);

	}
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

float4x4 m_WorldReflect;
float4x4 m_WorldReflectViewProj;
float reflector_height;


VS_OUT VS_Reflection(VS_IN vin)
{
	VS_OUT vout = (VS_OUT)0;

	vout.position = mul(float4(vin.position, 1.0f), m_WorldReflectViewProj);

	vout.ws_pos = mul(float4(vin.position, 1.0f),	m_WorldReflect);
	vout.normal = mul(float4(vin.normal, 0.0f),		m_WorldReflect).xyz;
	vout.tex =	  vin.tex;


	return vout;
}


float4 PS_Reflection(VS_OUT pin) : SV_TARGET
{
	
	float3 p0 = float3(0.0f, reflector_height+0.1f, 0.0f);
	float3 v = normalize(pin.ws_pos.xyz - p0);
	float dot_p = dot(v, float3(0.f, 1.f, 0.f));
	
	clip(-dot_p);

	
	float4 color = float4(0.0f, 0.0f, 0.0f, 1.0f);
	
	color = float4(shade(pin.ws_pos.xyz, normalize(pin.normal), 0), 1.0f);
			
	float4 ambient = float4(0.1f, 0.1f, 0.1f, 0.0f);

	if (mat_params.vIsTextured.x)
	{
		float4 tex_diff = tex_diffuse.Sample(s_linear, pin.tex);
		if (!bLit)
			return tex_diff;
		color *= tex_diff;
		ambient *= tex_diff;
	}

	// set alpha in w
	color = float4(color.xyz, mat_params.diffuse.w);

	color += ambient;

	return color;
}


RasterizerState rs_cullFront
{
	CullMode = Front;
};


technique10 Reflection 
{
    pass P0 
	{
        SetVertexShader( CompileShader( vs_4_0, VS_Reflection() ) );
		SetGeometryShader( NULL);
        SetPixelShader( CompileShader( ps_4_0, PS_Reflection() ) );

		SetRasterizerState(rs_cullFront);
	}
}

technique10 Reflection_CullFront
{
    pass P0 
	{
        SetVertexShader( CompileShader( vs_4_0, VS_Reflection() ) );
		SetGeometryShader( NULL);
        SetPixelShader( CompileShader( ps_4_0, PS_Reflection() ) );

		SetRasterizerState(rs_cullBack);
	}
}



//*******************************************R E F R A C T I O N S******************************************


float4x4 m_WorldRefract;
float4x4 m_WorldRefractViewProj;
float refractor_height;


VS_OUT VS_Refraction(VS_IN vin)
{
	VS_OUT vout = (VS_OUT)0;

	vout.position = mul(float4(vin.position, 1.0f), m_WorldRefractViewProj);

	vout.ws_pos = mul(float4(vin.position, 1.0f),	m_WorldRefract);
	vout.normal = mul(float4(vin.normal, 0.0f),		m_WorldRefract).xyz;
	vout.tex =	  vin.tex;

	return vout;
}


float4 PS_Refraction(VS_OUT pin) : SV_TARGET
{
	
	float3 p0 = float3(0.0f, refractor_height+0.2f, 0.0f);
	float3 v = normalize(pin.ws_pos.xyz - p0);
	float dot_p = dot(v, float3(0.f, 1.f, 0.f));
	

	dot_p *= -1.0f;
	
	clip(dot_p);

	
	float4 color = float4(0.0f, 0.0f, 0.0f, 1.0f);
	
	color = float4(shade(pin.ws_pos.xyz, normalize(pin.normal), 0), 1.0f);
			
	float4 ambient = float4(0.1f, 0.1f, 0.1f, 0.0f);

	if (mat_params.vIsTextured.x)
	{
		float4 tex_diff = tex_diffuse.Sample(s_linear, pin.tex);
		color *= tex_diff;
		ambient *= tex_diff;
	}

	// set alpha in w
	color = float4(color.xyz, mat_params.diffuse.w);

	color += ambient;

	return color;
}


technique10 Refraction
{
    pass P0 
	{
        SetVertexShader( CompileShader( vs_4_0, VS_Refraction() ) );
		SetGeometryShader( NULL);
        SetPixelShader( CompileShader( ps_4_0, PS_Refraction() ) );

		SetRasterizerState(rs_cullBack);
	}
}

